﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate;
using NHibernate.Transform;
using Thaire.Investment.BL.DTO;
using Thaire.Investment.BL.Filter;
using Thaire.Investment.BL.ScreenData;
using Thaire.Investment.Common;
using Thaire.Investment.Domains.Master;
using Thaire.Investment.Domains.Transaction;
using Thaire.Investment.Repository;

namespace Thaire.Investment.BL
{
    public class InstrumentBL
    {
        ISession _session;
        public InstrumentBL(ISession session)
        {
            _session = session;
        }

        #region common
        public IList<CounterParties> GetAllCounterPaties()
        {
            return new CounterPartiesRepo(_session).GetAll();
        }
        public IList<PaymentType> GetAllPaymentTypes()
        {
            return new PaymentTypeRepo(_session).GetAll();
        }
        #endregion

        #region Fixed Income Securities

        public AmortizeScheduleScreenData GetAmortizeScheduleScreenData(int headerID)
        {
            AmortizeScheduleScreenData scrData = new AmortizeScheduleScreenData();
            FixincomesecuritiesAmortizeScheduleRepo repo = new FixincomesecuritiesAmortizeScheduleRepo(_session);
            scrData.ScheduleList = repo.GetByFixIncomeHeaderID(headerID);
            scrData.FixIncomeSecuritiesDTO = GetFixIncomeHeaderByID(headerID);

            return scrData;
        }
        public void DeleteAmortizeSchedule(int amortizeScheduleID)
        {
            FixincomesecuritiesAmortizeScheduleRepo repo = new FixincomesecuritiesAmortizeScheduleRepo(_session);
            repo.DeleteByID(amortizeScheduleID);
        }
        public FixincomesecuritiesAmortizeSchedule InsertAmortizeSchedule(FixincomesecuritiesAmortizeSchedule data)
        {
            FixincomesecuritiesAmortizeScheduleRepo repo = new FixincomesecuritiesAmortizeScheduleRepo(_session);
            data.CreateDate = SessionManager.SystemDate;
            repo.Save(data);

            return data;
        }

        public FixIncomePurchaseScreenData GetFixIncomePurchaseScreenData()
        {

            FixIncomePurchaseScreenData scrdata = new FixIncomePurchaseScreenData();
            ReferenceCodeRepo refRepo = new ReferenceCodeRepo(_session);
            scrdata.PaymentTypeList = new PaymentTypeRepo(_session).GetAll().ToList();
            scrdata.PhysicalList = refRepo.GetByDomain(ReferenceCodeRepo.PHYSICAL);
            scrdata.KeepAtList = refRepo.GetByDomain(ReferenceCodeRepo.KEEP_AT);
            scrdata.RelateNonRelateList = refRepo.GetByDomain(ReferenceCodeRepo.RELATED_NONRELATED);
            scrdata.CounterPartiesList = new CounterPartiesRepo(_session).GetAll().ToList();
            scrdata.CurrencyList = new CurrencyRepo(_session).GetAll().OrderBy(x => x.CurrencySymbol).ToList();
            return scrdata;
        }

        public AmortizeScreenData GenerateAmortize(int fixIncomePurchaseID)
        {
            FixIncomeSecuritiesHeaderRepo headerRepo = new FixIncomeSecuritiesHeaderRepo(_session);
            FixIncomeSecuritiesPurchaseRepo purchaseRepo = new FixIncomeSecuritiesPurchaseRepo(_session);
            FixincomesecuritiesAmortizeHeaderRepo amortizeHeaderRepo = new FixincomesecuritiesAmortizeHeaderRepo(_session);
            FixincomesecuritiesAmortizeDetailRepo amortizeDetailRepo = new FixincomesecuritiesAmortizeDetailRepo(_session);
            AmortizeScreenData srcData = new AmortizeScreenData();
            FixincomesecuritiesPurchase purchase = purchaseRepo.GetByID(fixIncomePurchaseID);
            if (purchase == null)
                throw new Exception("ไม่พบ FixincomesecuritiesPurchase ");
            FixincomesecuritiesAmortizeHeader existHeader = amortizeHeaderRepo.GetByFixIncomeHeaderIDAndPurchaseID(purchase.FixincomesecuritiesHeaderId.GetValueOrDefault(), fixIncomePurchaseID);
            if (existHeader != null)
            {
                srcData.AmortizeHeader = existHeader;
                srcData.AmortizeDetailList = amortizeDetailRepo.GetByAmortizeHeaderID(existHeader.FixincomesecuritiesAmortizeHeaderID);
            }
            else
            {


                FixIncomeSecuritiesHeader header = headerRepo.GetByID(purchase.FixincomesecuritiesHeaderId.GetValueOrDefault());
                if (header == null)
                    throw new Exception("ไม่พบ FixIncomeSecuritiesHeader ");

                List<FixincomesecuritiesAmortizeDetail> details = new List<FixincomesecuritiesAmortizeDetail>();
                FixincomesecuritiesAmortizeHeader amortizeHeader = new FixincomesecuritiesAmortizeHeader();
                amortizeHeader.AI = purchase.AI;
                amortizeHeader.BookValue = purchase.GrossPrice;
                amortizeHeader.Coupon = header.Coupon;
                amortizeHeader.DiscountPremium = purchase.DiscountPremium;
                amortizeHeader.FixincomesecuritiesHeaderID = header.FixincomesecuritiesHeaderId;
                amortizeHeader.GrossPrice = purchase.GrossPrice;
                amortizeHeader.CleanPrice = purchase.CleanPrice;
                amortizeHeader.MaturityDate = header.MaturityDate;
                amortizeHeader.ParValue = purchase.ParValue;
                amortizeHeader.Symbol = header.Symbol;
                amortizeHeader.TradeDate = purchase.SettlementDate;
                amortizeHeader.Yield = purchase.Yield;
                amortizeHeader.FixincomesecuritiesPurchaseID = purchase.FixincomesecuritiesPurchaseId;
                amortizeHeader.IrrPerDay = (decimal)Calculator.IRRPerDay(amortizeHeader.BookValue.GetValueOrDefault(), amortizeHeader.ParValue.GetValueOrDefault(), amortizeHeader.Yield.GetValueOrDefault() / (decimal)100, amortizeHeader.MaturityDate.GetValueOrDefault(), amortizeHeader.TradeDate.GetValueOrDefault());
                if (!purchase.SettlementDate.HasValue)
                    throw new Exception("ไม่พบ TradeDate");

                if (!header.MaturityDate.HasValue)
                    throw new Exception("ไม่พบ MaturityDate");
                srcData.AmortizeHeader = amortizeHeader;

                DateTime endOfThisMonth = new DateTime(purchase.SettlementDate.GetValueOrDefault().Year, purchase.SettlementDate.GetValueOrDefault().Month, DateTime.DaysInMonth(purchase.SettlementDate.GetValueOrDefault().Year, purchase.SettlementDate.GetValueOrDefault().Month));
                int adjNextMonth = 1;
                if (purchase.SettlementDate.GetValueOrDefault().Date <= endOfThisMonth.Date)
                {
                    adjNextMonth = 0;
                }

                int allCalendarMonth = Calculator.MonthCalendarDifference(purchase.SettlementDate.GetValueOrDefault(), header.MaturityDate.GetValueOrDefault());
                if (adjNextMonth == 0)
                    allCalendarMonth += 1;

                FixincomesecuritiesAmortizeDetail previousRow = new FixincomesecuritiesAmortizeDetail();
                previousRow.FixincomesecuritiesAmortizeHeaderID = amortizeHeader.FixincomesecuritiesAmortizeHeaderID;
                previousRow.AmortizeDate = purchase.SettlementDate.GetValueOrDefault();
                previousRow.BookValue = purchase.CleanPrice.GetValueOrDefault();
                previousRow.Type = "Not Short";
                if (allCalendarMonth <= 12)
                {
                    previousRow.Type = "Short";
                }
                previousRow.Period = 0;
                details.Add(previousRow);


                for (int i = 0; i < allCalendarMonth; i++)
                {



                    DateTime nextMonth = purchase.SettlementDate.GetValueOrDefault().AddMonths(i + adjNextMonth);


                    DateTime endOfNextMonth = new DateTime(nextMonth.Year, nextMonth.Month, DateTime.DaysInMonth(nextMonth.Year, nextMonth.Month));
                    FixincomesecuritiesAmortizeDetail detail = new FixincomesecuritiesAmortizeDetail();
                    detail.FixincomesecuritiesAmortizeHeaderID = amortizeHeader.FixincomesecuritiesAmortizeHeaderID;
                    detail.Type = previousRow.Type;
                    detail.AmortizeDate = nextMonth.Date;
                    detail.Period = i + 1;

                    //  int dayinYear = 1;//ไม่ต้องหารต่อปีอีกแล้ว
                    int dayinYear = 365;
                    if (DateTime.IsLeapYear(endOfNextMonth.Year))
                    {
                        dayinYear = 366;
                    }

                    if (i == (allCalendarMonth - 1))//แถวสุดท้าย
                    {

                        detail.AmortizeDate = amortizeHeader.MaturityDate;
                        detail.NOOFDays = (int)detail.AmortizeDate.GetValueOrDefault().Subtract(previousRow.AmortizeDate.GetValueOrDefault()).TotalDays - 1;

                        detail.AmortiseOFInterest = (decimal)(amortizeHeader.ParValue.GetValueOrDefault() - previousRow.BookValue.GetValueOrDefault());
                        detail.DiscountPremium = detail.AmortiseOFInterest;
                        if (allCalendarMonth > 12)
                        {
                            detail.Coupon = (decimal)(((amortizeHeader.Coupon.GetValueOrDefault() / (decimal)100) * amortizeHeader.ParValue.GetValueOrDefault() * detail.NOOFDays.GetValueOrDefault()) / (decimal)dayinYear);
                            detail.Interest = (decimal)(((amortizeHeader.Yield.GetValueOrDefault() / (decimal)100) * previousRow.BookValue.GetValueOrDefault() * detail.NOOFDays.GetValueOrDefault()) / (decimal)dayinYear);
                        }

                        detail.BookValue = amortizeHeader.ParValue;

                    }
                    else
                    {
                        detail.AmortizeDate = endOfNextMonth;
                        if (detail.Period.GetValueOrDefault() == 1)
                        {
                            detail.NOOFDays = (int)endOfNextMonth.Subtract(previousRow.AmortizeDate.GetValueOrDefault()).TotalDays + 1;
                        }
                        else
                        {
                            detail.NOOFDays = (int)endOfNextMonth.Subtract(previousRow.AmortizeDate.GetValueOrDefault()).TotalDays;// +1;
                        }

                        if (allCalendarMonth > 12)
                        {
                            detail.Coupon = (decimal)(((amortizeHeader.Coupon.GetValueOrDefault() / (decimal)100) * amortizeHeader.ParValue.GetValueOrDefault() * detail.NOOFDays.GetValueOrDefault()) / (decimal)dayinYear);

                            detail.Interest = (decimal)(((amortizeHeader.Yield.GetValueOrDefault() / (decimal)100) * previousRow.BookValue.GetValueOrDefault() * detail.NOOFDays.GetValueOrDefault()) / (decimal)dayinYear);
                            detail.DiscountPremium = detail.Interest.GetValueOrDefault() - detail.Coupon.GetValueOrDefault();
                        }
                        detail.AmortiseOFInterest = (decimal)(amortizeHeader.IrrPerDay.GetValueOrDefault() * previousRow.BookValue.GetValueOrDefault() * detail.NOOFDays.GetValueOrDefault());
                        //   detail.NOOFDays = (int)endOfNextMonth.Subtract(previousRow.AmortizeDate.GetValueOrDefault()).TotalDays;// +1;
                        //if (allCalendarMonth > 12)
                        //{
                        //    detail.DiscountPremium = detail.Interest.GetValueOrDefault() - detail.Coupon.GetValueOrDefault();
                        //}
                        detail.BookValue = previousRow.BookValue.GetValueOrDefault() + detail.DiscountPremium.GetValueOrDefault() + detail.AmortiseOFInterest.GetValueOrDefault();




                    }



                    previousRow = detail;
                    details.Add(detail);

                }

                srcData.AmortizeDetailList = details;
            }

            return srcData;
            //int allMonth = purchase.TradeDate.GetValueOrDefault().Subtract(

            //  FixincomesecuritiesAmortizeDetail.cs
            //Microsoft.VisualBasic.Financial.IRR(ref irrArray, estimate);
            //    Math.Round(MidpointRounding.
        }


        /// <summary>
        /// fix income _sale,Guarantee
        /// </summary>
        /// <param name="purchaseID"></param>
        /// <returns></returns>
        public FixIncomeSecuritiesTransactionScreenData GetFixIncomeSecuritiesTransactionScreenData(int purchaseID, int? transactionID)
        {
            var data = new FixIncomeSecuritiesTransactionScreenData();
            data.FixincomesecuritiesPurchaseDTO = GetFixIncomePurchaseByID(purchaseID);
            data.CounterParties = new CounterPartiesRepo(_session).GetAll().ToList();
            data.TypeOfPayment = new PaymentTypeRepo(_session).GetAll().ToList();
            data.Obligations = new ObligationRepo(_session).GetAll().ToList();
            data.ObligationNOs = new ObligationNORepo(_session).GetAll().ToList();
            ReferenceCodeRepo refcodes = new ReferenceCodeRepo(_session);
            data.KeepAT = refcodes.GetByDomain(ReferenceCodeRepo.KEEP_AT);
            data.Physical = refcodes.GetByDomain(ReferenceCodeRepo.PHYSICAL);
            if (transactionID.GetValueOrDefault() > 0)
            {
                data.FixIncomeSecuritiesTransactionDTO = new FixIncomeSecuritiesTransactionDTO();
                data.FixIncomeSecuritiesTransactionDTO.FixIncomeSecuritiesTransaction = new FixIncomeSecuritiesTransactionRepo(_session).GetByID(transactionID.GetValueOrDefault());
            }
            return data;
        }

        /// <summary>
        /// fix income _sale get transaction
        /// </summary>
        /// <param name="transactionID"></param>
        /// <returns></returns>
        public FixIncomeSecuritiesTransactionDTO GetFixIncomeSecuritiesTransactionDTO(int transactionID)
        {
            FixIncomeSecuritiesTransactionDTO data = new FixIncomeSecuritiesTransactionDTO();
            data.FixIncomeSecuritiesTransaction = new FixIncomeSecuritiesTransactionRepo(_session).GetByID(transactionID);

            return data;
        }

        private void ValidateFixIncomeSecuritiesTransactionUnit(FixIncomeSecuritiesTransaction transaction)
        {
            var purchaseRepo = new FixIncomeSecuritiesPurchaseRepo(_session);
            var transactionRepo = new FixIncomeSecuritiesTransactionRepo(_session);
            var purchase = purchaseRepo.GetByID(transaction.PurchaseID);
            var tranList = transactionRepo.GetListByAndPurchaseID(transaction.PurchaseID);
            purchaseRepo.Evict(purchase);
            decimal sumSaleUnit = 0;
            decimal currSaleUnit = 0;
            foreach (var item in tranList)
            {
                transactionRepo.Evict(item);
                sumSaleUnit += item.Unit.GetValueOrDefault();
                if (item.TransactionID == transaction.TransactionID)
                {
                    currSaleUnit += item.Unit.GetValueOrDefault();
                }
            }

            if (transaction.TransactionID == 0)
            {
                if (sumSaleUnit + transaction.Unit.GetValueOrDefault() > purchase.Unit.GetValueOrDefault())
                {
                    if (transaction.TransactionType.ToUpper() == "GUARANTEE")
                        throw new Exception(string.Format("หน่วย (Unit) เหลือไม่พอสำหรับทำรายการ (เหลือ {0} Unit)", purchase.Unit.GetValueOrDefault() - sumSaleUnit));
                    throw new Exception(string.Format("ไม่สามารถขายได้เนื่องจากหน่วย (Unit) เหลือไม่พอกับจำนวนที่ขาย เหลือ {0} Unit", purchase.Unit.GetValueOrDefault() - sumSaleUnit));
                }
            }
            else
            {
                if ((sumSaleUnit - currSaleUnit) + transaction.Unit.GetValueOrDefault() > purchase.Unit.GetValueOrDefault())
                {
                    if (transaction.TransactionType.ToUpper() == "GUARANTEE")
                        throw new Exception(string.Format("หน่วย (Unit) เหลือไม่พอสำหรับทำรายการ (เหลือ {0} Unit)", purchase.Unit.GetValueOrDefault() - (sumSaleUnit - currSaleUnit)));

                    throw new Exception(string.Format("ไม่สามารถขายได้เนื่องจากหน่วย (Unit) เหลือไม่พอกับจำนวนที่ขาย เหลือ {0} Unit", purchase.Unit.GetValueOrDefault() - (sumSaleUnit - currSaleUnit)));
                }
            }

        }


        private void UpdateRemainAmtOfFixIncomeSecuritiesPuchase(int purchaseId)
        {
            var purchaseRepo = new FixIncomeSecuritiesPurchaseRepo(_session);
            var transactionRepo = new FixIncomeSecuritiesTransactionRepo(_session);
            var purchase = purchaseRepo.GetByID(purchaseId);
            var tranList = transactionRepo.GetListByAndPurchaseID(purchaseId);
            var sumUnit = 0;
            foreach (var item in tranList)
            {
                transactionRepo.Evict(item);
                sumUnit += item.Unit.GetValueOrDefault();
            }


            int oldUnit = purchase.Unit.GetValueOrDefault();
            purchase.RemainUnit = oldUnit - sumUnit;
            if (purchase.RemainUnit < 0)
                purchase.RemainUnit = 0;
            purchase.UpdateTs = SessionManager.SystemDate;
            purchaseRepo.Update(purchase);
        }

        /// <summary>
        /// fix income _sale, guarantee Insert
        /// </summary>
        /// <param name="transaction"></param>
        /// <returns></returns>
        public FixIncomeSecuritiesTransaction InsertFixIncomeSecuritiesTransaction(FixIncomeSecuritiesTransaction transaction)
        {
            ValidateFixIncomeSecuritiesTransactionUnit(transaction);
            // UpdateRemainAmtOfFixIncomeSecuritiesPuchase(transaction.PurchaseID);
            //var data = new FixIncomeSecuritiesTransactionDTO();
            transaction.CreateTs = SessionManager.SystemDate;
            new FixIncomeSecuritiesTransactionRepo(_session).Save(transaction);
            _session.Flush();
            UpdateRemainAmtOfFixIncomeSecuritiesPuchase(transaction.PurchaseID);
            return transaction;
        }


        /// <summary>
        /// fix income _sale Update
        /// </summary>
        /// <param name="transaction"> </param>
        /// <returns></returns>
        public FixIncomeSecuritiesTransaction UpdateFixIncomeSecuritiesTransaction(FixIncomeSecuritiesTransaction transaction)
        {
            ValidateFixIncomeSecuritiesTransactionUnit(transaction);



            //FixIncomeSecuritiesTransactionDTO data = new FixIncomeSecuritiesTransactionDTO();
            //transaction.m = SessionManager.SystemDate;
            new FixIncomeSecuritiesTransactionRepo(_session).Update(transaction);
            _session.Flush();
            UpdateRemainAmtOfFixIncomeSecuritiesPuchase(transaction.PurchaseID);

            return transaction;
        }
        public FixIncomeSecuritiesDTO InsertFixIncomeHeader(FixIncomeSecuritiesDTO headerData)
        {
            var operationDate = SessionManager.SystemDate; //SystemUtil.SysDate;
            FillFixIncomeSecuritiesHeaderData(headerData.Header);
            new FixIncomeSecuritiesHeaderRepo(_session).Save(headerData.Header);
            headerData.Header.CreateTs = operationDate;
            var ratingHistoryRepo = new RatingHistoryRepo(_session);
            if (headerData.RatingHistory != null)
            {
                headerData.RatingHistory.FinancialInstrumentId = headerData.Header.FixincomesecuritiesHeaderId;
                headerData.RatingHistory.FinancialInstrumentType = "FIXINCOMESECURITIES";
                headerData.RatingHistory.CreateTs = operationDate;
                ratingHistoryRepo.Save(headerData.RatingHistory);
            }
            _session.Flush();
            return headerData;
        }

        private void FillFixIncomeSecuritiesHeaderData(FixIncomeSecuritiesHeader header)
        {
            var comRepo = new CompanyRepo(_session);
            if (header.CompanyId.HasValue)
            {
                var com = comRepo.GetByID(header.CompanyId.Value);
                if (com != null)
                    header.CompanyName = com.CompanyNameTh;
            }
        }
        public List<RatingHistoryViewDTO> GetRatingHistory(int instrumentID, String instrumentType)
        {
            string sql = @"select z.type as RatingType , z.rating as Rate , ca_id as Agency , z.up_date  as UpdateDT 		
from (		
SELECT distinct 		
      [FINANCIAL_INSTRUMENT_ID]		
	  	   ,'ISSUE'  as type 
      ,[ISSUE_RATING] as rating 		
      ,[ISSUE_CREDIT_AGENCY] as ca_id 		
      ,[ISSUE_UPDATE_DATE] as up_date		
      ,[ISSUE_CREDIT_AGENCY_COUNTRY] as country 		
 FROM [investment].[dbo].[RATING_HISTORY]		
  where FINANCIAL_INSTRUMENT_ID =:instrumentID and FINANCIAL_INSTRUMENT_TYPE =:instrumentType and ISSUE_RATING is not null and [ISSUE_UPDATE_DATE] is not null 		
  union all 		
  SELECT distinct 		
       [FINANCIAL_INSTRUMENT_ID]		
	   	   ,'ISSUER'  as type 
       ,[ISSUER_RATING] as rating 		
      ,[ISSUER_CREDIT_AGENCY] as ca_id 		
      ,[ISSUER_UPDATE_DATE] as up_date		
      ,[ISSUER_CREDIT_AGENCY_COUNTRY]  as country 		
  FROM [investment].[dbo].[RATING_HISTORY]		
  where FINANCIAL_INSTRUMENT_ID =:instrumentID and FINANCIAL_INSTRUMENT_TYPE =:instrumentType and ISSUER_RATING  is not null and ISSUER_UPDATE_DATE is not null 		
  union all 		
  SELECT distinct 		
       [FINANCIAL_INSTRUMENT_ID]		
	   ,'GUARANTOR'  as type 	
      ,[GUARANTOR_RATING] as rating 		
      ,[GUARANTOR_CREDIT_AGENCY] as ca_id 		
      ,[GUARANTOR_UPDATE_DATE] as up_date		
      ,[GUARANTOR_CREDIT_AGENCY_COUNTRY]  as country 		
  FROM [investment].[dbo].[RATING_HISTORY]		
  where FINANCIAL_INSTRUMENT_ID =:instrumentID and FINANCIAL_INSTRUMENT_TYPE =:instrumentType and GUARANTOR_RATING  is not null and GUARANTOR_UPDATE_DATE is not null 		
    ) as z 
order by z.up_date desc		
";

            List<RatingHistoryViewDTO> data = new List<RatingHistoryViewDTO>();
            ISQLQuery query = _session.CreateSQLQuery(sql);
            query.SetAnsiString("instrumentType", instrumentType);
            query.SetInt32("instrumentID", instrumentID);
            query.SetResultTransformer(Transformers.AliasToBean(typeof(RatingHistoryViewDTO)));
            var result = query.List<RatingHistoryViewDTO>().ToList();
            return result;
        }
        public FixIncomeSecuritiesDTO UpdateFixIncomeHeader(FixIncomeSecuritiesDTO headerData)
        {
            var operationDate = SessionManager.SystemDate; //SystemUtil.SysDate;

            FillFixIncomeSecuritiesHeaderData(headerData.Header);
            FixIncomeSecuritiesHeaderRepo headerRepo = new FixIncomeSecuritiesHeaderRepo(_session);
            FixIncomeSecuritiesHeader oldHeader = headerRepo.GetByID(headerData.Header.FixincomesecuritiesHeaderId);
            headerRepo.Evict(oldHeader);
            if (headerData.Header.UpdateTs.GetValueOrDefault() != oldHeader.UpdateTs.GetValueOrDefault())
            {
                throw new Exception("ข้อมูลมีการเปลี่ยนแปลงโปรดดึงข้อมูลขึ้นมาใหม่อีกครั้ง");
            }
            headerData.Header.UpdateTs = operationDate;
            headerRepo.Update(headerData.Header);
            var ratingHistoryRepo = new RatingHistoryRepo(_session);
            if (headerData.RatingHistory != null)
            {
                CreditAgencyRepo cRepo = new CreditAgencyRepo(_session);

                headerData.RatingHistory.FinancialInstrumentId = headerData.Header.FixincomesecuritiesHeaderId;
                headerData.RatingHistory.CreateTs = operationDate;
                headerData.RatingHistory.FinancialInstrumentType = "FIXINCOMESECURITIES";
                //CreditAgency credit = null;
                //if (!String.IsNullOrEmpty(headerData.RatingHistory.IssueCreditAgency))
                //{
                //    credit = cRepo.GetByID(Convert.ToInt32(headerData.RatingHistory.IssueCreditAgency));
                //    if (credit != null)
                //    {
                //        headerData.RatingHistory.IssueCreditAgencyCountry = credit.CreditAgencyCountry;
                //    }
                //}
                //if (!String.IsNullOrEmpty(headerData.RatingHistory.IssuerCreditAgency))
                //{
                //    credit = cRepo.GetByID(Convert.ToInt32(headerData.RatingHistory.IssuerCreditAgency));
                //    if (credit != null)
                //    {
                //        headerData.RatingHistory.IssuerCreditAgencyCountry = credit.CreditAgencyCountry;
                //    }
                //}
                //if (!String.IsNullOrEmpty(headerData.RatingHistory.GuarantorCreditAgency))
                //{
                //    credit = cRepo.GetByID(Convert.ToInt32(headerData.RatingHistory.GuarantorCreditAgency));
                //    if (credit != null)
                //    {
                //        headerData.RatingHistory.GuarantorCreditAgencyCountry = credit.CreditAgencyCountry;
                //    }
                //}
                RatingHistory oldRatingHis = ratingHistoryRepo.GetByID(headerData.RatingHistory.RatingHistoryId);
                if (oldRatingHis != null)
                {
                    ratingHistoryRepo.Evict(oldRatingHis);
                    if (headerData.RatingHistory.DataKey() != oldRatingHis.DataKey())
                    {
                        ratingHistoryRepo.Save(headerData.RatingHistory);
                    }
                }
                else
                {
                    ratingHistoryRepo.Save(headerData.RatingHistory);
                }
            }
            _session.Flush();
            return headerData;
        }

        public FixedIncomeHeaderScreenData GetFixedIncomeHeaderScreenData()
        {
            var data = new FixedIncomeHeaderScreenData();
            data.Company = new CompanyRepo(_session).GetAll().ToList();
            data.Issuer = new IssuerRepo(_session).GetAll().ToList();
            data.InvolvedPartyType = new InvolvedPartyTypeRepo(_session).GetAll().ToList();
            data.GuaranteeType = new GuaranteeTypeRepo(_session).GetAll().ToList();
            data.GuarantorType = new GuarantorTypeRepo(_session).GetAll().ToList();
            data.Guarantor = new GuarantorRepo(_session).GetAll().ToList();
            data.Redemption = new RedemptionRepo(_session).GetAll().ToList();
            data.CalculationMethod = new CalculationMethodRepo(_session).GetAll().ToList();
            data.ListStatus = new ListStatusRepo(_session).GetAll().ToList();
            ReferenceCodeRepo refrepo = new ReferenceCodeRepo(_session);

            List<ReferenceCode> instrument = refrepo.GetByDomain(ReferenceCodeRepo.DOMAIN_FINANCIAL_INSTRUMENTS);
            ReferenceCode fixincomeRefCode = null;
            foreach (var item in instrument)
            {
                if (CommonUtil.GetInstrumentType(item.Key) == InstrumentType.FixedIncome)
                {
                    fixincomeRefCode = item;
                    break;
                }
            }


            data.IssuerType = refrepo.GetByDomain(ReferenceCodeRepo.ISSUER_TYPE, true);
            data.BondType = refrepo.GetByDomain(ReferenceCodeRepo.BOND_TYPE, true);
            data.Rating = refrepo.GetByDomain(ReferenceCodeRepo.RATING, true);

            if (data.Rating != null)
            {
                data.Rating = data.Rating.OrderBy(x => x.ValueEN).ToList();
            }

            data.CreditAgency = new CreditAgencyRepo(_session).GetAll().ToList();
           // data.CreditAgency = data.CreditAgency.OrderBy(x => x.CreditAgencyIssue).ToList();
            List<CreditAgency> distinctCreditAgency = new List<CreditAgency>();
            foreach (var item in data.CreditAgency)
            {
                if (distinctCreditAgency.Where(x => x.CreditAgencyIssue == item.CreditAgencyIssue).SingleOrDefault() == null)
                {
                    distinctCreditAgency.Add(item);
                }
            }

            data.CreditAgency = distinctCreditAgency;
            data.CreditAgency = data.CreditAgency.OrderBy(x => x.CreditAgencyIssue).ToList();

            if (fixincomeRefCode != null)
            {
                data.AssetClass = new AssetClassRepo(_session).GetListByFinancialInstrumentsReferenceCodeId(fixincomeRefCode.ID);
            }
            data.TransactionType = refrepo.GetByDomain(ReferenceCodeRepo.HEADER_TRANSACTION_TYPE);
            return data;
        }

        public int? GetRiskLevel(RatingHistory rateHistory)
        {
            if (rateHistory == null)
                return null;
            CreditAgencyRepo aRepo = new CreditAgencyRepo(_session);
            if (!string.IsNullOrEmpty(rateHistory.IssueRating) && !string.IsNullOrEmpty(rateHistory.IssueCreditAgency))
            {
                CreditAgency agency = aRepo.GetByRatingAndIssue(rateHistory.IssueRating, rateHistory.IssueCreditAgency);
                if (agency != null)
                    return agency.CreditAgencyRiskLevel;
            }

            if (!string.IsNullOrEmpty(rateHistory.IssuerRating) && !string.IsNullOrEmpty(rateHistory.IssuerCreditAgency))
            {
                CreditAgency agency = aRepo.GetByRatingAndIssue(rateHistory.IssuerRating, rateHistory.IssuerCreditAgency);
                if (agency != null)
                    return agency.CreditAgencyRiskLevel;
            }

            if (!string.IsNullOrEmpty(rateHistory.GuarantorRating) && !string.IsNullOrEmpty(rateHistory.GuarantorCreditAgency))
            {
                CreditAgency agency = aRepo.GetByRatingAndIssue(rateHistory.GuarantorRating, rateHistory.GuarantorCreditAgency);
                if (agency != null)
                    return agency.CreditAgencyRiskLevel;
            }
            return null;
        }

        public FixedIncomeListData GetFixedIncomeListScreenData()
        {
            var data = new FixedIncomeListData();
            data.Company = new CompanyRepo(_session).GetAll().ToList();
            data.Issuer = new IssuerRepo(_session).GetAll().ToList();
            data.IssuerType = new ReferenceCodeRepo(_session).GetByDomain(ReferenceCodeRepo.ISSUER_TYPE, true);

            return data;
        }
        public List<FixIncomeSecuritiesHeader> SearchFiexdIncome(SearchFiexdIncomeFilter searchData)
        {

            IQueryOver<FixIncomeSecuritiesHeader, FixIncomeSecuritiesHeader> query = _session.QueryOver<FixIncomeSecuritiesHeader>()
               .Where(x => x.FixincomesecuritiesHeaderId == x.FixincomesecuritiesHeaderId);

            if (searchData.Company.HasValue)
                query.And(x => x.CompanyId == searchData.Company.Value);
            if (searchData.Issuer.HasValue)
                query.And(x => x.IssuerId == searchData.Issuer.Value);
            if (searchData.IssuerType.HasValue)
                query.And(x => x.IssuerTypeId == searchData.IssuerType);
            if (searchData.IssueTerm.HasValue)
                query.And(x => x.IssuerTerm == searchData.IssueTerm.Value);
            if (!String.IsNullOrEmpty(searchData.Symbol))
                query.And(x => x.Symbol == searchData.Symbol);
            return new List<FixIncomeSecuritiesHeader>(query.List());
        }

        public FixincomesecuritiesPurchaseDTO GetFixIncomePurchaseByID(int purchaseID)
        {
            var dto = new FixincomesecuritiesPurchaseDTO();
            dto.Purhcase = new FixIncomeSecuritiesPurchaseRepo(_session).GetByID(purchaseID);
            if (dto.Purhcase != null)
            {
                dto.Header = GetFixIncomeHeaderByID(dto.Purhcase.FixincomesecuritiesHeaderId.GetValueOrDefault());





            }


            return dto;
        }

        public FixIncomeSecuritiesDTO GetFixIncomeHeaderByID(int id)
        {
            var dto = new FixIncomeSecuritiesDTO();
            var repo = new FixIncomeSecuritiesHeaderRepo(_session);
            ReferenceCodeRepo refRepo = new ReferenceCodeRepo(_session);
            dto.Header = repo.GetByID(id);
            List<RatingHistory> ratingData = repo.GetRatingHistory(id);
            if (ratingData.Count > 0)
            {
                dto.RatingHistory = ratingData[ratingData.Count - 1];
                if (dto.RatingHistory != null)
                {
                    CreditAgencyRepo creditRepo = new CreditAgencyRepo(_session);
                    List<ReferenceCode> refcodeList = refRepo.GetByDomain(ReferenceCodeRepo.RATING, true);

                    dto.CreditAgencyIssueName = creditRepo.GetName(DataConverter.ConvertStringToIntNull(dto.RatingHistory.IssueCreditAgency));
                    dto.CreditAgencyIssuerName = creditRepo.GetName(DataConverter.ConvertStringToIntNull(dto.RatingHistory.IssuerCreditAgency));
                    dto.CreditAgencyGuarantorName = creditRepo.GetName(DataConverter.ConvertStringToIntNull(dto.RatingHistory.GuarantorCreditAgency));

                }

            }
            dto.TransactionHistory = GetFixIncomeTransaction(id);



            return dto;
        }


        private List<InstructionDataDTO> GetFixIncomeTransaction(int fixIncomeHeaderID)
        {
            #region sql
            String Sql = @"select 
                        H.FIXINCOMESECURITIES_HEADER_ID as FixincomeHeaderID,
                        P.FIXINCOMESECURITIES_PURCHASE_ID as  PurchaseID,
                        0 as TransactionID,
                        H.ISSUER_TERM as IssuerTerm,
                        P.REF_NO as RefNo,
                        H.MATURITY_DATE as MaturityDate,
                        H.ISIN_CODE as IsinCode,
                        H.SYMBOL as Symbol,
                        P.TRANSACTION_TYPE as TransactionType , 
                        P.COUNTERPARTY_ID as CounterPartyID,
                        P.COUNTERPARTY_NAME as CounterParty , 
                        case when H.MATURITY_DATE <= getdate() then 0 
                        else 
                          convert(decimal(12,2), DATEDIFF(m, H.MATURITY_DATE , getdate())/12.00) 
                        end as TimeToMaturityDate , 
                        P.TRADE_DATE as TradeDate, 
                        P.SETTLEMENT_DATE as  SettlementDate, 
                        P.UNIT as  TransactionUnit, 
                        P.REMAIN_UNIT as  RemainUnit, 
                        P.PAR as Par , 
                        P.YIELD as  CostYieldYTM, 
                        H.COUPON_PAYMENT_DATE as  CouponPaymentDate, 
                        H.COUPON as Coupon , 
                        P.PURCHASE_VALUE_TH as PurchaseValueLocalTHB , 
                        case P.TRANSACTION_TYPE 
                        when 'Purchase' then 1 
                        when 'Subscription' then 2 end as OrderTrans 
                        from 
                        FIXINCOMESECURITIES_HEADER H, 
                        FIXINCOMESECURITIES_PURCHASE P
                        where 
                        P.FIXINCOMESECURITIES_HEADER_ID =  H.FIXINCOMESECURITIES_HEADER_ID AND  H.FIXINCOMESECURITIES_HEADER_ID =:FIXINCOMESECURITIES_HEADER_ID
                        union all
                        select 
                        H.FIXINCOMESECURITIES_HEADER_ID as FixincomeHeaderID,
                        P.FIXINCOMESECURITIES_PURCHASE_ID as  PurchaseID,
                        T.TRANSACTION_ID as TransactionID,
                        H.ISSUER_TERM as IssuerTerm,
                        T.REF_NO as RefNo,
                        H.MATURITY_DATE as MaturityDate,
                        H.ISIN_CODE as IsinCode,
                        H.SYMBOL as Symbol,
                        T.TRANSACTION_TYPE as TransactionType , 
                        T.COUNTERPARTY_ID as CounterPartyID,
                        T.COUNTERPARTY_NAME  as  CounterParty , 
                        case when H.MATURITY_DATE <= getdate() then 0 
                        else 
                          convert(decimal(12,2), DATEDIFF(m, H.MATURITY_DATE , getdate())/12.00) 
                        end as  TimeToMaturityDate ,  
                        T.TRADE_DATE as  TradeDate,   
                        T.SETTLEMENT_DATE as SettlementDate, 
                        T.UNIT as TransactionUnit,
                        P.REMAIN_UNIT as RemainUnit, 
                        P.PAR as Par,
                        T.YIELD as CostYieldYTM,
                        H.COUPON_PAYMENT_DATE as CouponPaymentDate,
                        H.COUPON as Coupon,
                        P.PURCHASE_VALUE_TH as PurchaseValueLocalTHB ,
                        3 as Order_Trans 
                        from
                        FIXINCOMESECURITIES_PURCHASE P, 
                        FIXINCOMESECURITIES_HEADER H, 
                        FIXINCOMESECURITIES_TRANSACTION T
                        where
                        P.FIXINCOMESECURITIES_HEADER_ID =  H.FIXINCOMESECURITIES_HEADER_ID   
                        and P.FIXINCOMESECURITIES_PURCHASE_ID  =  T.PURCHASE_ID
                        AND  H.FIXINCOMESECURITIES_HEADER_ID =:FIXINCOMESECURITIES_HEADER_ID 

                        order by OrderTrans";
            #endregion
            ISQLQuery sqlQuery = _session.CreateSQLQuery(Sql);
            sqlQuery.SetParameter("FIXINCOMESECURITIES_HEADER_ID", fixIncomeHeaderID);
            List<InstructionDataDTO> result = sqlQuery.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(InstructionDataDTO))).List<InstructionDataDTO>().ToList();
            foreach (var item in result)
            {
                item.TimeToMaturityDate = (decimal)Calculator.CalTime2Mature(item.MaturityDate.GetValueOrDefault(), SessionManager.SystemDate);
            }
            return result;
        }

        public List<FixincomesecuritiesPurchase> GetFixIncomePurchasesByHeaderId(int headerId)
        {
            var result = new FixIncomeSecuritiesPurchaseRepo(_session).GetListByHeaderId(headerId);
            return result;
        }

        public FixIncomeSecuritiesHeader GetFixedIncomeSecuritiesHeaderById(int headerId)
        {
            return new FixIncomeSecuritiesHeaderRepo(_session).GetByID(headerId);
        }

        public FixincomesecuritiesPurchase InsertFixedIncomePurchase(FixincomesecuritiesPurchase fixincomesecuritiesPurchase)
        {
            var repo = new FixIncomeSecuritiesPurchaseRepo(_session);
            var operationDate = SessionManager.SystemDate; //SystemUtil.SysDate;
            //var operationDate = SystemUtil.SysDate;
            fixincomesecuritiesPurchase.RemainUnit = fixincomesecuritiesPurchase.Unit;
            fixincomesecuritiesPurchase.GrossPrice = fixincomesecuritiesPurchase.CleanPrice.GetValueOrDefault() + fixincomesecuritiesPurchase.AI.GetValueOrDefault();
            fixincomesecuritiesPurchase.CreateTs = operationDate;
            _session.Save(fixincomesecuritiesPurchase);
            return fixincomesecuritiesPurchase;
        }
        internal FixincomesecuritiesPurchase UpdateFixincomesecuritiesPurchase(FixincomesecuritiesPurchase purchase)
        {


            FixIncomeSecuritiesPurchaseRepo purchaseRepo = new FixIncomeSecuritiesPurchaseRepo(_session);
            var transactionRepo = new FixIncomeSecuritiesTransactionRepo(_session);


            FixincomesecuritiesPurchase oldPurchase = purchaseRepo.GetByID(purchase.FixincomesecuritiesPurchaseId);
            purchaseRepo.Evict(oldPurchase);
            if (purchase.UpdateTs.GetValueOrDefault() != oldPurchase.UpdateTs.GetValueOrDefault())
            {
                throw new Exception("ข้อมูลมีการเปลี่ยนแปลงโปรดดึงข้อมูลขึ้นมาใหม่อีกครั้ง");
            }

            purchase.UpdateTs = SessionManager.SystemDate;
            var tranList = transactionRepo.GetListByAndPurchaseID(purchase.FixincomesecuritiesPurchaseId);
            var sumUnit = 0;
            foreach (var item in tranList)
            {
                transactionRepo.Evict(item);
                sumUnit += item.Unit.GetValueOrDefault();
            }
            if (purchase.Unit < sumUnit)
            {
                //  throw new Exception("จำนวน unit ที่ระบุมาน้อยกว่าจำนวน unit รวมที่ได้ขายไปแล้วโปรดระบุให้มากกว่า " + sumUnit);
            }
            purchase.GrossPrice = purchase.CleanPrice.GetValueOrDefault() + purchase.AI.GetValueOrDefault();

            purchaseRepo.Update(purchase);
            _session.Flush();
            UpdateRemainAmtOfFixIncomeSecuritiesPuchase(purchase.FixincomesecuritiesPurchaseId);
            return purchase;
        }
        #endregion


        #region Unit Truse


        public UnitTrustProportionScreenData GetUnitTrustProportionScreenData(int? headerId, int? proportionId)
        {
            var data = new UnitTrustProportionScreenData();
            if (proportionId != null)
            {
                data.Proportion = new UnitTrustProportionRepo(SessionManager.CurrentSession).GetByID(proportionId.Value);
                if (headerId != null && headerId.Value != data.Proportion.UnitTrustHeaderID)
                    throw new Exception(string.Format("Unit Trust {0} is not equals the parameter value : {1}", data.Proportion.UnitTrustHeaderID, headerId.Value));
            }
            if (headerId != null)
            {
                data.HeaderDTO = new UnitTrustHeaderDTO
                {
                    Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                    Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value)
                };
            }
            else
            {
                if (proportionId.HasValue && data.Proportion != null)
                {
                    data.HeaderDTO = new UnitTrustHeaderDTO
                    {
                        Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(data.Proportion.UnitTrustHeaderID.GetValueOrDefault()),
                        Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Proportion.UnitTrustHeaderID.GetValueOrDefault()),
                        Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Proportion.UnitTrustHeaderID.GetValueOrDefault()),
                        Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Proportion.UnitTrustHeaderID.GetValueOrDefault()),
                        Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Proportion.UnitTrustHeaderID.GetValueOrDefault())
                    };
                }
            }
            if (null == data.HeaderDTO)
            {
                throw new Exception(string.Format("UnitTrust Header ID : {0} was not found.", headerId));
            }

            return data;
        }

        public UnitTrustProportion InsertUnitTrustPrivilege(UnitTrustProportion data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var repo = new UnitTrustProportionRepo(_session);
            repo.Save(data);
            _session.Flush();
            return data;
        }

        public UnitTrustProportion UpdateUnitTrustProportion(UnitTrustProportion data)
        {
            var repo = new UnitTrustProportionRepo(_session);
            var temp = repo.GetByID(data.ID);
            if (temp == null)
                throw new Exception(string.Format("Proportion ID : {0} was not found.", data.ID));
            //concurrency control
            if (temp.ModifyDate != data.ModifyDate)
                throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            _session.Flush();
            return data;
        }

        public List<UnitTrustHeader> SearchUnitTrust(SearchUnitTrustFilter searchData)
        {
            IQueryOver<UnitTrustHeader, UnitTrustHeader> query = _session.QueryOver<UnitTrustHeader>()
               .Where(x => x.ID == x.ID);

            if (searchData.Company.HasValue)
                query.And(x => x.UnitTrustCompanyID == searchData.Company.Value);
            if (searchData.AssetManagement.HasValue)
                query.And(x => x.AssetMgmtID == searchData.AssetManagement.Value);
            if (!String.IsNullOrEmpty(searchData.FundName))
                query.And(x => x.FundName == searchData.FundName);
            if (!String.IsNullOrEmpty(searchData.Symbol))
                query.And(x => x.Symbol == searchData.Symbol);
            query.OrderBy(x => x.CreateDate);
            return new List<UnitTrustHeader>(query.List());
        }

        public UnitTrustTransactionScreenData GetUnitTrustTransactionScreenData(int? headerId, int? transactionId, string transactionType)
        {
            var data = new UnitTrustTransactionScreenData();
            if (transactionId != null)
            {
                data.Transaction = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetByID(transactionId.Value);
                if (headerId != null && headerId.Value != data.Transaction.UnitTrustTransactionHeaderID)
                    throw new Exception(string.Format("Unit Trust {0} is not equals the parameter value : {1}", data.Transaction.UnitTrustTransactionHeaderID, headerId.Value));
            }

            if (headerId != null)
            {
                data.HeaderDTO = new UnitTrustHeaderDTO
                {
                    Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                    Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value)
                };
            }
            else
            {
                if (transactionId.HasValue && data.Transaction != null)
                {
                    data.HeaderDTO = new UnitTrustHeaderDTO
                    {
                        Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(data.Transaction.UnitTrustTransactionHeaderID),
                        Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Transaction.UnitTrustTransactionHeaderID),
                        Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Transaction.UnitTrustTransactionHeaderID),
                        Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Transaction.UnitTrustTransactionHeaderID),
                        Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Transaction.UnitTrustTransactionHeaderID)
                    };
                }
            }
            if (null == data.HeaderDTO)
            {
                throw new Exception(string.Format("UnitTrust Header ID : {0} was not found.", headerId));
            }

            if (transactionType.ToUpper() == "GUARANTEE")
            {
                data.Obligations = new ObligationRepo(_session).GetAll().ToList();
                data.ObligationNOs = new ObligationNORepo(_session).GetAll().ToList();
            }
            else
            {
                data.PaymentTypes = new PaymentTypeRepo(_session).GetAll().ToList();
            }

            return data;
        }

        public UnitTrustTransaction InsertUnitTrustTransaction(UnitTrustTransaction data)
        {
            data.CreateDate = SessionManager.SystemDate;
            new UnitTrustTransactionRepo(_session).Save(data);
            _session.Flush();
            return data;
        }

        public UnitTrustTransaction UpdateUnitTrustTransaction(UnitTrustTransaction data)
        {
            var repo = new UnitTrustTransactionRepo(_session);
            var temp = repo.GetByID(data.ID);
            if (temp == null)
                throw new Exception(string.Format("Privilege ID : {0} was not found.", data.ID));
            ////concurrency control
            //if (temp.ModifyDate  != data.ModifyDate)
            //    throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            _session.Flush();
            return data;
        }

        public UnitTrustHeaderDTO InsertUnitTrustHeader(UnitTrustHeader data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var comRepo = new CompanyRepo(_session);
            var uTrustRepo = new UnitTrustHeaderRepo(_session);
            //if (data.UnitTrustCompanyID.HasValue)
            //{
            //    var com = comRepo.GetByID(data.UnitTrustCompanyID.Value);
            //    if (com != null)
            //        data.UnitTrustCompanyName = com.CompanyNameTh;
            //}

            uTrustRepo.Save(data);
            _session.Flush();

            //insert bid/Nav
            if (data.ListedStatus.ToUpper() == "LISTED")
            {
                if (data.BidPrice != null)
                {
                    var bidRepo = new UnitTrustBidRepo(_session);
                    bidRepo.Save(new UnitTrustBid()
                                     {Bid = data.BidPrice, Date = data.BidPriceDate, UnitTrustHeaderID = data.ID});
                }
            }
            else if (data.ListedStatus.ToUpper() == "NON LISTED")
            {
                if (data.Nav != null)
                {
                    var bidRepo = new UnitTrustNavRepo(_session);
                    bidRepo.Save(new UnitTrustNav() {Nav = data.Nav, Date = data.NavDate, UnitTrustHeaderID = data.ID});
                }
            }
            else
            {
                throw new Exception("Listed Status cannot be null.");
            }

            //insert par
            var parRepo = new UnitTrustParRepo(_session);
            parRepo.Save(new UnitTrustPar() { Par = data.Par, Date = data.ParDate, UnitTrustHeaderID = data.ID });

            //insert fund name
            SaveFundName(data.FundName, "TH");
            SaveFundName(data.FundNameEn, "EN");

            var result = new UnitTrustHeaderDTO
            {
                Header = data,
                Transactions =
                    new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID)
            };
            return result;
        }

        private FundNameRepo _fundNameRepo;
        void SaveFundName(string fundName, string lang)
        {
            if (_fundNameRepo == null)
                _fundNameRepo = new FundNameRepo(_session);
            var data = _fundNameRepo.GetFundNameByNameAndLang(fundName, lang);
            if (data == null || data.Count == 0)
            {
                _fundNameRepo.Save(new FundName() { Name = fundName, Lang = lang});
            }
        }

        public UnitTrustHeaderDTO UpdateUnitTrustHeader(UnitTrustHeader data)
        {
            var uTrustRepo = new UnitTrustHeaderRepo(_session);
            var tempHeader = uTrustRepo.GetByID(data.ID);
            if (tempHeader == null)
                throw new Exception("Header was not found with ID : " + data.ID);
            if (data.ModifyDate != tempHeader.ModifyDate)
                throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error old:{0} - new:{1})", tempHeader.ModifyDate, data.ModifyDate));

            data.ModifyDate = SessionManager.SystemDate;
            //insert histories
            if (tempHeader.ListedStatus != data.ListedStatus)
            {
                //insert bid/Nav
                if (data.ListedStatus.ToUpper() == "LISTED")
                {
                    var bidRepo = new UnitTrustBidRepo(_session);
                    bidRepo.Save(new UnitTrustBid() { Bid = data.BidPrice, Date = data.BidPriceDate, UnitTrustHeaderID = data.ID });
                }
                else if (data.ListedStatus.ToUpper() == "NON LISTED")
                {
                    var bidRepo = new UnitTrustNavRepo(_session);
                    bidRepo.Save(new UnitTrustNav() { Nav = data.Nav, Date = data.NavDate, UnitTrustHeaderID = data.ID });
                }
                else
                {
                    throw new Exception("Listed Status cannot supprot a value : " + data.ListedStatus);
                }
            }
            else
            {
                //insert bid/Nav
                if (data.ListedStatus.ToUpper() == "LISTED" && (tempHeader.BidPrice == null || tempHeader.BidPrice != data.BidPrice))
                {
                    var bidRepo = new UnitTrustBidRepo(_session);
                    bidRepo.Save(new UnitTrustBid() { Bid = data.BidPrice, Date = data.BidPriceDate, UnitTrustHeaderID = data.ID });
                }
                if (data.ListedStatus.ToUpper() == "NON LISTED" && (tempHeader.Nav == null || tempHeader.Nav != data.Nav))
                {
                    var bidRepo = new UnitTrustNavRepo(_session);
                    bidRepo.Save(new UnitTrustNav() { Nav = data.Nav, Date = data.NavDate, UnitTrustHeaderID = data.ID });
                }
            }

            if (tempHeader.Par != data.Par)
            {
                //insert par
                var parRepo = new UnitTrustParRepo(_session);
                parRepo.Save(new UnitTrustPar() { Par = data.Par, Date = data.ParDate, UnitTrustHeaderID = data.ID });
            }

            //insert fund name
            SaveFundName(data.FundName, "TH");
            SaveFundName(data.FundNameEn, "EN");

            //if (data.UnitTrustCompanyID.HasValue)
            //{
            //    var comRepo = new CompanyRepo(_session);
            //    var com = comRepo.GetByID(data.UnitTrustCompanyID.Value);
            //    if (com != null)
            //        data.UnitTrustCompanyName = com.CompanyNameTh;
            //}
            _session.Evict(tempHeader);
            uTrustRepo.Update(data);
            _session.Flush();
            var result = new UnitTrustHeaderDTO
                             {
                                 Header = data,
                                 Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID),
                                 Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID),
                                 Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID),
                                 Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID)
                             };
            return result;
        }

        public UnitTrustHeaderScreenData GetUnitTrustHeaderScreenData(int? headerId)
        {
            var data = new UnitTrustHeaderScreenData();
            if (headerId != null)
            {
                data.HeaderDTO = new UnitTrustHeaderDTO
                {
                    Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                    Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value)
                };
            }
            data.Companies = new CompanyRepo(_session).GetAll().ToList();
            data.AssetManagementCompanies = new AssetManagementCompanyRepo(_session).GetAll().ToList();
            data.InvolvedPartyTypes = new InvolvedPartyTypeRepo(_session).GetAll().ToList();
            data.ListStatuses = new ListStatusRepo(_session).GetAll().ToList();
            var refrepo = new ReferenceCodeRepo(_session);
            data.RelatedOrNonRelateds = refrepo.GetByDomain(ReferenceCodeRepo.RELATED_NONRELATED, false);
            data.GroupOfTypes = refrepo.GetByDomain(ReferenceCodeRepo.TYPE_GROUP, false);
            data.Types = refrepo.GetByDomain(ReferenceCodeRepo.UNITTRUST_TYPE, false);
            return data;
        }

        public UnitTrustHeaderDTO GetPrivilegeDataByHeaderId(int headerId)
        {
            var header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(headerId);
            if (null == header)
            {
                throw new Exception(string.Format("UnitTrust Header ID : {0} was not found.", headerId));
            }
            var privileges = new UnitTrustPrivilegeRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId);
            return new UnitTrustHeaderDTO() { Header = header, Privileges = privileges };
        }

        public UnitTrustPrivilegeScreenData GetUnitTrustPrivilegeScreenData(int? headerId, int? privilegeId)
        {
            var data = new UnitTrustPrivilegeScreenData();
            if (privilegeId != null)
            {
                data.Privilege = new UnitTrustPrivilegeRepo(SessionManager.CurrentSession).GetByID(privilegeId.Value);
                if (headerId != null && headerId.Value != data.Privilege.UnitTrustHeaderID)
                    throw new Exception(string.Format("Unit Trust {0} is not equals the parameter value : {1}", data.Privilege.UnitTrustHeaderID, headerId.Value));
            }

            if (headerId != null)
            {
                data.HeaderDTO = new UnitTrustHeaderDTO
                {
                    Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                    Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value)
                };
            }
            else
            {
                if (privilegeId.HasValue && data.Privilege != null)
                {
                    data.HeaderDTO = new UnitTrustHeaderDTO
                    {
                        Header = new UnitTrustHeaderRepo(SessionManager.CurrentSession).GetByID(data.Privilege.UnitTrustHeaderID.GetValueOrDefault()),
                        Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Privilege.UnitTrustHeaderID.GetValueOrDefault()),
                        Bids = new UnitTrustBidRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Privilege.UnitTrustHeaderID.GetValueOrDefault()),
                        Navs = new UnitTrustNavRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Privilege.UnitTrustHeaderID.GetValueOrDefault()),
                        Pars = new UnitTrustParRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Privilege.UnitTrustHeaderID.GetValueOrDefault())
                    };
                }
            }
            if (null == data.HeaderDTO)
            {
                throw new Exception(string.Format("UnitTrust Header ID : {0} was not found.", headerId));
            }
            if (privilegeId.HasValue)
            {
                data.Privilege = new UnitTrustPrivilegeRepo(SessionManager.CurrentSession).GetByID(privilegeId.Value);
            }

            data.PaymentTypes = new PaymentTypeRepo(_session).GetAll().ToList();
            return data;
        }

        public UnitTrustPrivilege InsertUnitTrustPrivilege(UnitTrustPrivilege data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var repo = new UnitTrustPrivilegeRepo(_session);
            repo.Save(data);
            _session.Flush();
            return data;
        }

        public UnitTrustPrivilege UpdateUnitTrustPrivilege(UnitTrustPrivilege data)
        {
            var repo = new UnitTrustPrivilegeRepo(_session);
            var temp = repo.GetByID(data.ID);
            if (temp == null)
                throw new Exception(string.Format("Privilege ID : {0} was not found.", data.ID));
            ////concurrency control
            //if (temp.ModifyDate  != data.ModifyDate)
            //    throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            _session.Flush();
            return data;
        }

        public List<FundName> GetFundThNamesByName(string fundThName)
        {
            if (_fundNameRepo == null)
                _fundNameRepo = new FundNameRepo(_session);
            return _fundNameRepo.GetFundThNamesByName(fundThName);
        }

        public List<FundName> GetFundEnNamesByName(string fundEnName)
        {
            if (_fundNameRepo == null)
                _fundNameRepo = new FundNameRepo(_session);
            return _fundNameRepo.GetFundEnNamesByName(fundEnName);
        }

        #endregion

        #region Loans
        public IList<District> GetDistrictsByProvinceId(int? provinceId)
        {
            //todo: NotImplementedException
            throw new NotImplementedException();
        }
        public IList<SubDistrict> GetSubDistrictsByProvinceId(int? districtId)
        {
            //todo: NotImplementedException
            throw new NotImplementedException();
        }

        public LoansExtrainstallment InsertLoansExtrainstallment(LoansExtrainstallment data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var repo = new LoansExtrainstallmentRepo(_session);
            repo.Save(data);
            _session.Flush();
            return data;
        }

        public LoansExtrainstallment UpdateLoansExtrainstallment(LoansExtrainstallment data)
        {
            var repo = new LoansExtrainstallmentRepo(_session);
            var temp = repo.GetByID(data.LoansExtrainstallmentID);
            if (temp == null)
                throw new Exception(string.Format("Extra Installment  ID : {0} was not found.", data.LoansExtrainstallmentID));
            //concurrency control
            if (temp.ModifyDate != data.ModifyDate)
                throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error {0} : {1})", temp.ModifyDate, data.ModifyDate));
            _session.Evict(temp);
            data.ModifyDate = SessionManager.SystemDate;
            repo.Update(data);
            _session.Flush();
            return data;
        }

        public LoanExtraInstallmentScreenData GetLoanExtraInstallmentScreenData(int? headerId, int? extraInstallmentId)
        {
            var data = new LoanExtraInstallmentScreenData();
            if (extraInstallmentId != null)
            {
                data.Extrainstallment = new LoansExtrainstallmentRepo(SessionManager.CurrentSession).GetByID(extraInstallmentId.Value);
                if (headerId != null && headerId.Value != data.Extrainstallment.LoansHeaderID)
                    throw new Exception(string.Format("Loans {0} is not equals the parameter value : {1}", data.Extrainstallment.LoansHeaderID, headerId.Value));
            }

            if (headerId != null)
            {
                data.HeaderDTO = new LoanHeaderDTO
                {
                    Header = new LoansHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                };
            }
            else
            {
                if (extraInstallmentId.HasValue && data.Extrainstallment != null)
                {
                    data.HeaderDTO = new LoanHeaderDTO
                    {
                        Header = new LoansHeaderRepo(SessionManager.CurrentSession).GetByID(data.Extrainstallment.LoansHeaderID.GetValueOrDefault())
                        //Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.Transaction.UnitTrustTransactionHeaderID)
                    };
                }
            }
            if (null == data.HeaderDTO)
            {
                throw new Exception(string.Format("Loans Header ID : {0} was not found.", headerId));
            }
            data.HeaderDTO.Period = Calculator.CalPeriodYearAndMonth(data.HeaderDTO.Header.ContractStartDate, data.HeaderDTO.Header.ContractEndDate);

            //TODO: spec ไม่เคลียร์
            data.HeaderDTO.Installment =Calculator.CalLoanInstallment(data.HeaderDTO.Header.ContractAmount.GetValueOrDefault(), 1,Calculator.CountDiffMonthBetweenStartAndEndDate(data.HeaderDTO.Header.ContractStartDate,data.HeaderDTO.Header.ContractEndDate).GetValueOrDefault());

            return data;
        }

        public List<LoansHeader> SearchLoans(SearchLoanFilter filter)
        {
            var query = _session.QueryOver<LoansHeader>()
               .Where(x => x.LoansHeaderID == x.LoansHeaderID);
            if (filter.Company.HasValue)
                query.And(x => x.CompanyID == filter.Company.Value);
            if (filter.LoanType.HasValue)
                query.And(x => x.LoanTypeID == filter.LoanType.Value);
            if (!String.IsNullOrEmpty(filter.ContractNumber))
                query.And(x => x.ContractNumber == filter.ContractNumber);
            if (!String.IsNullOrEmpty(filter.BorrowerName))
                query.And(x => x.BorrowerName == filter.BorrowerName);
            if (filter.LoanBalanceStart.HasValue)
                query.And(x => x.ContractAmount >= filter.LoanBalanceStart.Value);
            if (filter.LoanBalanceEnd.HasValue)
                query.And(x => x.ContractAmount <= filter.LoanBalanceEnd.Value);
            if (filter.ContractStartDate.HasValue)
                query.And(x => x.ContractStartDate >= filter.ContractStartDate.Value);
            if (filter.ContractEndDate.HasValue)
                query.And(x => x.ContractEndDate <= filter.ContractEndDate.Value);

            if (!String.IsNullOrEmpty(filter.Status))
            {
                if (filter.Status == "Pending")
                    query.And(x => x.BorrowerName == "Alive");
                if (filter.Status == "Closed")
                    query.And(x => x.BorrowerName == "Matured");
            }
            query.OrderBy(x => x.CreateDate);
            return new List<LoansHeader>(query.List());
        }

        public LoanHeaderScreenData GetLoanHeaderScreenData(int? headerId, bool isSearchMode)
        {
            var data = new LoanHeaderScreenData();
            if (headerId != null)
            {
                data.HeaderDTO = new LoanHeaderDTO
                {
                    Header = new LoansHeaderRepo(SessionManager.CurrentSession).GetByID(headerId.Value),
                    LoansExtrainstallments = new LoansExtrainstallmentRepo(SessionManager.CurrentSession).GetListByHeaderID(headerId.Value),
                    LoansInterestDetails = new LoansInterestDetailRepo(SessionManager.CurrentSession).GetListByHeaderId(headerId.Value)
                };
            }
            var refrepo = new ReferenceCodeRepo(_session);
            data.Companies = new CompanyRepo(_session).GetAll().ToList();
            data.LoanTypes = refrepo.GetByDomain(ReferenceCodeRepo.LOAN_TYPE, false);
            if (isSearchMode)
            {
                data.Statuses = refrepo.GetByDomain(ReferenceCodeRepo.LOAN_STATUS, false);
            }
            else
            {
                data.InvolvedPartyTypes = new InvolvedPartyTypeRepo(_session).GetAll().ToList();
                data.Objectives = refrepo.GetByDomain(ReferenceCodeRepo.LOAN_OBJECTIVE, false);
                data.GuaranteeTypes = refrepo.GetByDomain(ReferenceCodeRepo.GUARANTEE_TYPE, false);
                data.AssessmentMortgates = refrepo.GetByDomain(ReferenceCodeRepo.ASSESSMENT_MORTGATE, false);
                data.Occupations = new OccupationRepo(_session).GetAll().ToList();
                //todo: ขาดการดึงข้อมูลอื่นๆ
                //data.Provinces
                //data.Owners
                //data.Districts
                //data.SubDistricts

            }

            return data;
        }

        public LoanHeaderDTO InsertLoanHeader(LoansHeader data)
        {
            data.CreateDate = SessionManager.SystemDate;
            var comRepo = new CompanyRepo(_session);
            var uTrustRepo = new LoansHeaderRepo(_session);
            //if (data.UnitTrustCompanyID.HasValue)
            //{
            //    var com = comRepo.GetByID(data.UnitTrustCompanyID.Value);
            //    if (com != null)
            //        data.UnitTrustCompanyName = com.CompanyNameTh;
            //}

            uTrustRepo.Save(data);
            _session.Flush();

            //todo: ขาดการดึงข้อมูลอื่นๆ
            var result = new LoanHeaderDTO
            {
                Header = data
                //Transactions = new UnitTrustTransactionRepo(SessionManager.CurrentSession).GetListByHeaderID(data.ID)
            };
            return result;
        }

        public LoanHeaderDTO UpdateLoanHeader(LoansHeader data)
        {
            var uTrustRepo = new LoansHeaderRepo(_session);
            var tempHeader = uTrustRepo.GetByID(data.LoansHeaderID);
            if (tempHeader == null)
                throw new Exception("Header was not found with ID : " + data.LoansHeaderID);
            if (data.ModifyDate != tempHeader.ModifyDate)
                throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error old:{0} - new:{1})", tempHeader.ModifyDate, data.ModifyDate));

            data.ModifyDate = SessionManager.SystemDate;

            _session.Evict(tempHeader);
            uTrustRepo.Update(data);
            _session.Flush();

            var result = new LoanHeaderDTO
            {
                Header = data
            };
            return result;
        }

        public LoanInterestRateScreenData GetLoanInterestRateScreenData(int? headerId)
        {
            var data = new LoanInterestRateScreenData();
            if (headerId.GetValueOrDefault() != 0)
            {

                data.Header = new LoansHeaderRepo(_session).GetByID(headerId.Value);
                data.Interests = new LoansInterestDetailRepo(_session).GetListByHeaderId(headerId.Value);


            }
            return data;
        }

        public LoansInterestDetail InsertInterestRateDetail(LoansInterestDetail detail)
        {

            detail.CreateDate = SessionManager.SystemDate;
            new LoansInterestDetailRepo(_session).Save(detail);

            return detail;
        }
        public LoansInterestDetail UpdateInterestRateDetail(LoansInterestDetail data)
        {
            var repo = new LoansInterestDetailRepo(_session);
            var temp = repo.GetByID(data.LoansInterestDetailID);
            if (temp == null)
                throw new Exception("LoansInterest was not found with ID : " + data.LoansInterestDetailID);
            if (data.ModifyDate != temp.ModifyDate)
                throw new Exception(string.Format("Update Timestamp failed. (Concurrency control Error old:{0} - new:{1})", temp.ModifyDate, data.ModifyDate));

            temp.ModifyDate = SessionManager.SystemDate;
            temp.ModifyBY = data.ModifyBY;
            temp.InterestRate = data.InterestRate;
            temp.MlrDate = data.MlrDate;
            temp.MlrMinus = data.MlrMinus;
            temp.MlrRate = data.MlrRate;
            temp.UpdateInfo = data.UpdateInfo;
            temp.InterestPeriod = data.InterestPeriod;
            temp.Installment = data.Installment;
            repo.Update(data);
            _session.Flush();

            return temp;
        }
        public AmortizeLoanScheduleScreenData GetAmortizeLoanScheduleScreenData(int interestDetailID)
        {
            var insDetailRepo = new LoansInterestDetailRepo(_session);
            var detail = insDetailRepo.GetByID(interestDetailID);
            var scrData = new AmortizeLoanScheduleScreenData
                              {
                                  LoanHeaderDTO = new LoanHeaderDTO
                                                      {
                                                          Header =
                                                              new LoansHeaderRepo(SessionManager.CurrentSession).GetByID
                                                              (detail.InterestHeaderID.GetValueOrDefault())
                                                      },
                                  Installment = detail.Installment,
                                  Period = detail.InterestPeriod.GetValueOrDefault(),
                                  LoansAmortizeDetail = GenerateAmortizeLoanSchedule(detail.LoansInterestDetailID)
                              };
            return scrData;     
        }


        private List<LoansAmortizeDetail> GenerateAmortizeLoanSchedule(int interestDetailID)
        {
            List<LoansAmortizeDetail> amortizeData = new List<LoansAmortizeDetail>();
            LoansInterestDetailRepo insDetailRepo = new LoansInterestDetailRepo(_session);
            LoansInterestDetail detail = insDetailRepo.GetByID(interestDetailID);
            LoansHeader header = new LoansHeaderRepo(SessionManager.CurrentSession).GetByID(detail.InterestHeaderID.GetValueOrDefault());
            int? calMonth = Calculator.CountDiffMonthBetweenStartAndEndDate(header.ContractStartDate, header.ContractEndDate);
            if (calMonth.GetValueOrDefault() == 0)
            {
                throw new Exception("PeriodCal IsZero ไม่สามารถคำนวนค่างวดได้");
            }
            DateTime peviousDate = header.ContractStartDate.GetValueOrDefault().Date;
            decimal beginBal = header.ContractAmount.GetValueOrDefault();
            LoansAmortizeDetail peviousData = null;
            for (int i = 1; i <= calMonth; i++)
            {
                if (i == 1)
                {
                    DateTime endOfMonth = CommonUtil.GetLastDayOfMonth(header.ContractStartDate.GetValueOrDefault()); //new DateTime(header.ContractStartDate.GetValueOrDefault().Year, header.ContractStartDate.GetValueOrDefault().Month, DateTime.DaysInMonth(header.ContractStartDate.GetValueOrDefault().Year, header.ContractStartDate.GetValueOrDefault().Month));
                    LoansAmortizeDetail loansAmortizeDetail = new LoansAmortizeDetail();
                    loansAmortizeDetail.InterestID = detail.LoansInterestDetailID;
                    loansAmortizeDetail.LoansHeaderID = detail.InterestHeaderID;
                    loansAmortizeDetail.Period = i;
                    loansAmortizeDetail.Date = endOfMonth;
                    loansAmortizeDetail.NOOFDays = (int)endOfMonth.Subtract(peviousDate).TotalDays + 1;
                    loansAmortizeDetail.InterestRate = detail.InterestRate;
                    loansAmortizeDetail.BeginningBalance = beginBal;
                    loansAmortizeDetail.Installment = Calculator.CalLoanInstallment(header.ContractAmount.GetValueOrDefault(), loansAmortizeDetail.InterestRate.GetValueOrDefault(), calMonth.GetValueOrDefault());
                    //    loansAmortizeDetail.Interest = loansAmortizeDetail.InterestRate.GetValueOrDefault() * loansAmortizeDetail.NOOFDays.GetValueOrDefault();
                    loansAmortizeDetail.Interest = ((loansAmortizeDetail.BeginningBalance.GetValueOrDefault() * (loansAmortizeDetail.InterestRate.GetValueOrDefault() / (decimal)100)) / (decimal)365) * loansAmortizeDetail.NOOFDays.GetValueOrDefault();

                    loansAmortizeDetail.Principal = loansAmortizeDetail.Installment.GetValueOrDefault() - loansAmortizeDetail.Interest.GetValueOrDefault();
                    loansAmortizeDetail.EndingBalance = loansAmortizeDetail.BeginningBalance.GetValueOrDefault() - loansAmortizeDetail.Principal;
                    loansAmortizeDetail.PeriodCal = calMonth;
                    peviousData = loansAmortizeDetail;
                    amortizeData.Add(loansAmortizeDetail);
                }
                else
                {
                    LoansAmortizeDetail loansAmortizeDetail = new LoansAmortizeDetail();
                    DateTime endOfMonth = CommonUtil.GetLastDayOfMonth(peviousData.Date.GetValueOrDefault().AddDays(1));

                    loansAmortizeDetail.InterestID = detail.LoansInterestDetailID;
                    loansAmortizeDetail.LoansHeaderID = detail.InterestHeaderID;
                    loansAmortizeDetail.Period = i;
                    loansAmortizeDetail.Date = endOfMonth;
                    loansAmortizeDetail.NOOFDays = (int)endOfMonth.Subtract(peviousData.Date.GetValueOrDefault()).TotalDays;
                    loansAmortizeDetail.InterestRate = detail.InterestRate;
                    loansAmortizeDetail.BeginningBalance = peviousData.EndingBalance;
                    loansAmortizeDetail.Installment = peviousData.Installment;
                    //     loansAmortizeDetail.Interest = loansAmortizeDetail.InterestRate.GetValueOrDefault() * loansAmortizeDetail.NOOFDays.GetValueOrDefault();
                    loansAmortizeDetail.Interest = ((loansAmortizeDetail.BeginningBalance.GetValueOrDefault() * (loansAmortizeDetail.InterestRate.GetValueOrDefault() / (decimal)100)) / (decimal)365) * loansAmortizeDetail.NOOFDays.GetValueOrDefault();
                    loansAmortizeDetail.Principal = loansAmortizeDetail.Installment.GetValueOrDefault() - loansAmortizeDetail.Interest.GetValueOrDefault();
                    loansAmortizeDetail.EndingBalance = loansAmortizeDetail.BeginningBalance.GetValueOrDefault() - loansAmortizeDetail.Principal;
                    loansAmortizeDetail.PeriodCal = calMonth;
                    peviousData = loansAmortizeDetail;
                    amortizeData.Add(loansAmortizeDetail);
                }


            }
            return amortizeData;
        }
        #endregion


    }
}
